using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;
using submgr = Microsoft.Dss.Services.SubscriptionManager;
using Microsoft.Dss.Core;
using Microsoft.Dss.Core.DsspHttp;
using System.Windows;
using Microsoft.Ccr.Adapters.WinForms;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using vision = HCC.Robotics.Services.HCCGenericVisionModule.Proxy;
using Microsoft.Dss.Services.ControlPanel;

namespace HCC.Robotics.HCCRefereeModule
{
    [Contract(Contract.Identifier)]
    [DisplayName("HCCRefereeModule")]
    [Description("HCCRefereeModule service")]
    class HCCRefereeModuleService : DsspServiceBase
    {
        [ServiceState(StateTransform = "HCC.Robotics.HCCRefereeModule.Resources.Transform.xslt")]
        [InitialStatePartner(Optional = true, ServiceUri = "HCCRefereeModule.Config.xml")]
        HCCRefereeModuleState _state = null;

        [ServicePort("/HCCReferee", AllowMultipleInstances = false)]
        HCCRefereeModuleOperations _mainPort = new HCCRefereeModuleOperations();

        [SubscriptionManagerPartner]
        submgr.SubscriptionManagerPort _submgrPort = new submgr.SubscriptionManagerPort();

        [Partner("Vision", Contract = vision.Contract.Identifier, CreationPolicy = PartnerCreationPolicy.UsePartnerListEntry, Optional = false)]
        vision.HCCGenericVisionModuleOperations _visionPort = new vision.HCCGenericVisionModuleOperations();
        vision.HCCGenericVisionModuleOperations _visionNotify = new vision.HCCGenericVisionModuleOperations();

        /// <summary>
        /// Windows form stuff
        /// </summary>
        RefereeBox _refereeBox = null;
        FromWinformEvents _fromWinformPort = new FromWinformEvents();

        public HCCRefereeModuleService(DsspServiceCreationPort creationPort)
            : base(creationPort)
        {
        }

        protected override void Start()
        {
            if (_state == null)
            {
                _state = new HCCRefereeModuleState();
                _state.Configuration = new GameConfig();
                _state.Configuration.FirstHalfTime = 30;
                _state.Configuration.HalfTime = 5;
                _state.Configuration.SecondHalfTime = 30;
                _state.Configuration.YellowCardTime = 5;
                _state.Configuration.TimeoutLimit = 10;
                _state.Configuration.NumberOfTimeouts = 4;

                SaveState(_state);
            }

            b1a = false;
            b2a = false;
            y1a = false;
            y2a = false;

            _state.GameState = GameState.Init;

            base.Start();

            MainPortInterleave.CombineWith(new Interleave(
                new TeardownReceiverGroup(),
                new ExclusiveReceiverGroup
                    (
                        Arbiter.Receive<FromWinformMsg>(true, _fromWinformPort, OnWinformMessageHandler),
                        Arbiter.Receive<vision.VisionDataUpdate>(true, _visionNotify, OnVisionNotifyHandler)
                    ),
                new ConcurrentReceiverGroup()
            ));

            _visionPort.Subscribe(_visionNotify);

            WinFormsServicePort.Post(new RunForm(CreateForm));
        }

        public Form CreateForm()
        {
            return new RefereeBox(_fromWinformPort, _state.Configuration);
        }

        // to indicate that the player may move.
        private bool b1a, b2a, y1a, y2a;
        void OnVisionNotifyHandler(vision.VisionDataUpdate data)
        {
            GameData gameData = new GameData();
            gameData.Ball = new BallData();
            gameData.Ball.Ball = new Position(data.Body.Data.BallX, data.Body.Data.BallY);
            gameData.FieldData = new FieldDataClass();
            gameData.FieldData.LeftGoalLower = new Position(data.Body.Data.LeftGoalLowerX, data.Body.Data.LeftGoalLowerY);
            gameData.FieldData.LeftGoalUpper = new Position(data.Body.Data.LeftGoalUpperX, data.Body.Data.LeftGoalUpperY);
            gameData.FieldData.RightGoalLower = new Position(data.Body.Data.RightGoalLowerX, data.Body.Data.RightGoalLowerY);
            gameData.FieldData.RightGoalUpper = new Position(data.Body.Data.RightGoalUpperX, data.Body.Data.RightGoalUpperY);
            gameData.FieldData.LeftLower = new Position(data.Body.Data.BottomLeftX, data.Body.Data.BottomLeftY);
            gameData.FieldData.LeftUpper = new Position(data.Body.Data.TopLeftX, data.Body.Data.TopLeftY);
            gameData.FieldData.RightLower = new Position(data.Body.Data.BottomRightX, data.Body.Data.BottomRightY);
            gameData.FieldData.RightUpper = new Position(data.Body.Data.TopRightX, data.Body.Data.TopRightY);
            gameData.Players = new PlayerData();
            gameData.Players.BluePlayer1 = new Position(data.Body.Data.BluePlayer1X, data.Body.Data.BluePlayer1Y);
            gameData.Players.BluePlayer1Heading = data.Body.Data.BluePlayer1H;
            gameData.Players.BluePlayer2 = new Position(data.Body.Data.BluePlayer2X, data.Body.Data.BluePlayer2Y);
            gameData.Players.BluePlayer2Heading = data.Body.Data.BluePlayer2H;
            gameData.Players.YellowPlayer1 = new Position(data.Body.Data.YellowPlayer1X, data.Body.Data.YellowPlayer1Y);
            gameData.Players.YellowPlayer1Heading = data.Body.Data.YellowPlayer1H;
            gameData.Players.YellowPlayer2 = new Position(data.Body.Data.YellowPlayer2X, data.Body.Data.YellowPlayer2Y);
            gameData.Players.YellowPlayer2Heading = data.Body.Data.YellowPlayer2H;
            // ID: 359
            gameData.Players.IsFirstHalf = _state.IsFirstHalf;
            // ID: 359
            gameData.State = new GameStateDataClass();
            gameData.State.BluePlayer1Active = b1a;
            gameData.State.BluePlayer2Active = b2a;
            gameData.State.YellowPlayer1Active = y1a;
            gameData.State.YellowPlayer2Active = y2a;
            gameData.Config = _state.Configuration;
            gameData.TimeStamp = data.Body.Data.TimeStamp;

            _mainPort.Post(new GameDataUpdate(gameData));

            data.ResponsePort.Post(DefaultUpdateResponseType.Instance);
        }

        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public IEnumerator<ITask> SetColorHandler(SetColor setColor)
        {
            if (_state.GameState == GameState.WaitingForPlayers)
            {
                if (setColor.Body.Team == Team.Blue && !_state.Blue)
                {
                    _state.Blue = true;
                    SetStatus("Waiting for Yellow Team ...");
                    if (_state.Blue && _state.Yellow)
                    {
                        SetStatus("Ready for game ...");
                        _state.GameState = GameState.ReadyForGame;
                    }
                    setColor.ResponsePort.Post(DefaultUpdateResponseType.Instance);
                    yield break;
                }
                if (setColor.Body.Team == Team.Yellow && !_state.Yellow)
                {
                    _state.Yellow = true;
                    SetStatus("Waiting for Blue Team ...");
                    if (_state.Blue && _state.Yellow)
                    {
                        SetStatus("Ready for game ...");
                        _state.GameState = GameState.ReadyForGame;
                    }
                    setColor.ResponsePort.Post(DefaultUpdateResponseType.Instance);
                    yield break;
                }
                _state.TotalPlayers--;
                _state.GameState = GameState.WaitingForPlayers;
                setColor.ResponsePort.Post(new Fault());
            }
            yield break;
        }

        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public IEnumerator<ITask> GameUpdateHandler(GameDataUpdate gameDataUpdate)
        {
            SendNotification(_submgrPort, gameDataUpdate);
            gameDataUpdate.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            yield break;
        }

        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public IEnumerator<ITask> SubscribeHandler(Subscribe subscribe)
        {
            if (_state.GameState == GameState.WaitingForPlayers)
            {
                LogInfo(LogGroups.Console, "Subscribe request from: " + subscribe.Body.Subscriber);
                yield return Arbiter.Choice(
                    SubscribeHelper(_submgrPort, subscribe.Body, subscribe.ResponsePort),
                    delegate(SuccessResult success)
                    {
                        LogInfo(LogGroups.Console, "Subscribe Successfull");
                        _state.TotalPlayers++;
                    },
                    delegate(Exception e)
                    {
                        LogError(LogGroups.PartnerManagement, "Subscribe failed", e);
                    }
                );
            }
            else
            {
                LogInfo(LogGroups.Console, "Subscribe request from: " + subscribe.Body.Subscriber + " but i'am not Waiting for players!!!");
                subscribe.ResponsePort.Post(new Fault());
            }

            yield break;
        }

        #region Windows form functions

        void OnWinformMessageHandler(FromWinformMsg msg)
        {
            switch (msg.Command)
            {
                case FromWinformMsg.MsgEnum.Loaded:
                    _refereeBox = (RefereeBox)msg.Object;
                    _state.GameState = GameState.WaitingForPlayers;
                    SetStatus("Waiting for Teams ...");
                    break;
                case FromWinformMsg.MsgEnum.ActivePlayers:
                    bool.TryParse(msg.Parameters[0], out y1a);
                    bool.TryParse(msg.Parameters[1], out y2a);
                    bool.TryParse(msg.Parameters[2], out b1a);
                    bool.TryParse(msg.Parameters[3], out b2a);
                    break;
                case FromWinformMsg.MsgEnum.Exit:
                    ControlPanelPort.Post(new DropProcess());
                    break;
                // ID: 359
                case FromWinformMsg.MsgEnum.SetFirstHalf:
                    _state.IsFirstHalf = true;
                    break;
                case FromWinformMsg.MsgEnum.SetSecondHalf:
                    _state.IsFirstHalf = false;
                    break;
                // ID: 359
            }
        }

        public void SetStatus(string status)
        {
            if (_refereeBox != null)
            {
                WinFormsServicePort.FormInvoke(
                        delegate()
                        {
                            _refereeBox.SetStatus(status);
                        }
                    );
            }
        }

        #endregion
    }
}


